1 S. cerevisiae sample estimation of all samples (old and new)

This document should make clear the suitability of our yeast data for differential expression analyses. It should also give some ideas about the depth and distribution of the data.

2 Gathering samples

Later, we will likely choose to exclude one of the three experimental batches in the data. Therefore, I am making three expressionsets, one with all data, and one the various subsets.

merged_expt <- sm(create_expt(metadata="sample_sheets/all_samples.xlsx",
                              gene_info=sc_all_annotations,
                              file_column="allfile"))
## Don't forget, I need to change the condition names.
only_old <- subset_expt(merged_expt, subset="batch=='E1'")
## There were 24, now there are 8 samples.
merged_new <- subset_expt(merged_expt, subset="batch!='E1'")
## There were 24, now there are 16 samples.
merged_nor <- subset_expt(merged_expt, subset="batch!='E2B1'")
## There were 24, now there are 16 samples.
merged_nos <- subset_expt(merged_expt, subset="batch!='E2B2'")
## There were 24, now there are 16 samples.

3 Visualizing raw data

There are lots of methods we have to examine raw data and explore stuff like batch effects or non-canonical distributions or skewed counts. hpgltools provides some functionality to make this process easier. The graphs shown below and many more are generated with the wrapper ‘graph_metrics()’, when invoked it provides a list of plots including: library sizes, the number of non-zero genes, density/box plots by sample, distance/correlation heatmaps, standard median correlation/distance, PCA/TSNE clustering, top-n genes, a legend describing the colors/symbols used, and some tables describing the data. Optionally, it can also perform quantile-quantile plots showing the distribution of each sample vs. the median of all samples and MA plots of the same.

Caveat: some plots do not work well with gene IDs that are all-0, thus I first filter the data to remove them.

I also added a neat function ‘plot_libsize_prepost()’ which shows how many genes are poorly represented before/after filtering the data.

The plots printed here are all metrics which are useful when considering raw data.

merged_filt <- sm(normalize_expt(merged_expt, filter=TRUE))
merged_metrics <- sm(graph_metrics(merged_expt))

pp(file="illustrator_input/01_legend.pdf", image=merged_metrics$legend)
## Writing the image to: illustrator_input/01_legend.pdf and calling dev.off().
pp(file="illustrator_input/02_raw_libsize.pdf", image=merged_metrics$libsize)
## Writing the image to: illustrator_input/02_raw_libsize.pdf and calling dev.off().

prepost <- plot_libsize_prepost(merged_expt)
pp(file="illustrator_input/03_libsize_changed_lowgenes.pdf", image=prepost$lowgene_plot)
## Writing the image to: illustrator_input/03_libsize_changed_lowgenes.pdf and calling dev.off().

pp(file="illustrator_input/04_nonzero_genes.pdf", image=merged_metrics$nonzero)
## Writing the image to: illustrator_input/04_nonzero_genes.pdf and calling dev.off().

pp(file="illustrator_input/05_raw_boxplot.pdf", image=merged_metrics$boxplot)
## Writing the image to: illustrator_input/05_raw_boxplot.pdf and calling dev.off().

pp(file="illustrator_input/06_raw_density.pdf", image=merged_metrics$density)
## Writing the image to: illustrator_input/06_raw_density.pdf and calling dev.off().

pp(file="illustrator_input/07_raw_boxplot.pdf", image=merged_metrics$boxplot)
## Writing the image to: illustrator_input/07_raw_boxplot.pdf and calling dev.off().

pp(file="illustrator_input/08_topn.pdf", image=merged_metrics$topnplot)
## Writing the image to: illustrator_input/08_topn.pdf and calling dev.off().

4 Normalize and visualize

Other metrics are more useful when used with data on the log scale and normalized by number of reads/library and/or by quantile.

merged_norm <- normalize_expt(merged_expt, transform="log2", convert="cpm", filter=TRUE)
## This function will replace the expt$expressionset slot with:
## log2(cpm(hpgl(data)))
## It backs up the current data into a slot named:
##  expt$backup_expressionset. It will also save copies of each step along the way
##  in expt$normalized with the corresponding libsizes. Keep the libsizes in mind
##  when invoking limma.  The appropriate libsize is the non-log(cpm(normalized)).
##  This is most likely kept at:
##  'new_expt$normalized$intermediate_counts$normalization$libsizes'
##  A copy of this may also be found at:
##  new_expt$best_libsize
## Leaving the data unnormalized.  This is necessary for DESeq, but
##  EdgeR/limma might benefit from normalization.  Good choices include quantile,
##  size-factor, tmm, etc.
## Not correcting the count-data for batch effects.  If batch is
##  included in EdgerR/limma's model, then this is probably wise; but in extreme
##  batch effects this is a good parameter to play with.
## Step 1: performing count filter with option: hpgl
## Removing 1030 low-count genes (6095 remaining).
## Step 2: not normalizing the data.
## Step 3: converting the data with cpm.
## Step 4: transforming the data with log2.
## transform_counts: Found 1152 values equal to 0, adding 1 to the matrix.
## Step 5: not doing batch correction.
merged_metrics <- graph_metrics(merged_norm)
## Graphing number of non-zero genes with respect to CPM by library.
## Graphing library sizes.
## Graphing a boxplot.
## Graphing a correlation heatmap.
## Graphing a standard median correlation.
## Performing correlation.
## Graphing a distance heatmap.
## Graphing a standard median distance.
## Performing distance.
## Graphing a PCA plot.
## Graphing a T-SNE plot.
## Plotting a density plot.
## Plotting the representation of the top-n genes.
## Printing a color to condition legend.

The data should now be normalized, lets view some metrics post-facto.

pp(file="illustrator_input/09_norm_corheat.pdf", image=merged_metrics$corheat)
## Writing the image to: illustrator_input/09_norm_corheat.pdf and calling dev.off().

pp(file="illustrator_input/10_norm_disheat.pdf", image=merged_metrics$disheat)
## Writing the image to: illustrator_input/10_norm_disheat.pdf and calling dev.off().

## It appears that just the normalization is sufficient to split the samples completely by type and deeply separate them from the heterologous samples

pp(file="illustrator_input/11_norm_smc.pdf", image=merged_metrics$smc)
## Writing the image to: illustrator_input/11_norm_smc.pdf and calling dev.off().

pp(file="illustrator_input/12_norm_smd.pdf", image=merged_metrics$smd)
## Writing the image to: illustrator_input/12_norm_smd.pdf and calling dev.off().

## The samples are very well behaved, none fall below the red line.

pp(file="illustrator_input/13_norm_pca.pdf", image=merged_metrics$pcaplot)
## Writing the image to: illustrator_input/13_norm_pca.pdf and calling dev.off().

pp(file="illustrator_input/14_norm_tsne.pdf", image=merged_metrics$tsneplot)
## Writing the image to: illustrator_input/14_norm_tsne.pdf and calling dev.off().

## The homogeneous wt/mutant are nicely separated, and what is more, the exogeneous samples also split wt/mutant, that might prove to be quite useful.

5 Now look at the data without batch ‘E2B1’

nor_norm <- sm(normalize_expt(merged_nor, transform="log2", convert="cpm", norm="quant", filter=TRUE))
nor_plots <- sm(graph_metrics(nor_norm))
nor_batchnorm <- sm(normalize_expt(merged_nor, transform="log2", convert="cpm", norm="quant", filter=TRUE,
                                batch="fsva"))
nor_batchplots <- sm(graph_metrics(nor_batchnorm))

6 Try many batch estimation methods to see what is up.

I do not think any of this information is currently being used, so I am going to stop running it for the moment but keep it here in case we decide to revive it.

merged_pcabatch <- sm(normalize_expt(merged_expt, transform="log2",
                                filter=TRUE, batch="pca", low_to_zero=TRUE))
merged_pcabatch_metrics <- sm(graph_metrics(merged_pcabatch))

merged_nor_pcabatch <- sm(normalize_expt(merged_nor, transform="log2",
                                filter=TRUE, batch="pca", low_to_zero=TRUE))
merged_nor_pcabatch_metrics <- sm(graph_metrics(merged_nor_pcabatch))

merged_nos_pcabatch <- sm(normalize_expt(merged_nos, transform="log2",
                                filter=TRUE, batch="pca", low_to_zero=TRUE))
merged_nos_pcabatch_metrics <- sm(graph_metrics(merged_nos_pcabatch))

merged_sva <- sm(normalize_expt(merged_expt, transform="log2",
                                filter=TRUE, batch="sva", low_to_zero=TRUE))
merged_sva_metrics <- sm(graph_metrics(merged_sva))

merged_nor_sva <- sm(normalize_expt(merged_nor, transform="log2",
                                filter=TRUE, batch="sva", low_to_zero=TRUE))
merged_nor_sva_metrics <- sm(graph_metrics(merged_nor_sva))

merged_nos_sva <- sm(normalize_expt(merged_nos, transform="log2",
                                filter=TRUE, batch="sva", low_to_zero=TRUE))
merged_nos_sva_metrics <- sm(graph_metrics(merged_nos_sva))

merged_combat <- sm(normalize_expt(merged_expt, transform="log2",
                                   filter=TRUE, batch="combat_scale", low_to_zero=TRUE))
merged_combat_metrics <- sm(graph_metrics(merged_combat))

merged_nor_combat <- sm(normalize_expt(merged_nor, transform="log2",
                                   filter=TRUE, batch="combat_scale", low_to_zero=TRUE))
merged_nor_combat_metrics <- sm(graph_metrics(merged_nor_combat))

merged_nos_combat <- sm(normalize_expt(merged_nos, transform="log2",
                                   filter=TRUE, batch="combat_scale", low_to_zero=TRUE))
merged_nos_combat_metrics <- sm(graph_metrics(merged_nos_combat))

merged_limma <- sm(normalize_expt(merged_expt, transform="log2",
                                   filter=TRUE, batch="limmaresid", low_to_zero=TRUE))
merged_limma_metrics <- sm(graph_metrics(merged_limma))

merged_nor_limma <- sm(normalize_expt(merged_nor, transform="log2",
                                   filter=TRUE, batch="limmaresid", low_to_zero=TRUE))
merged_nor_limma_metrics <- sm(graph_metrics(merged_nor_limma))

merged_nos_limma <- sm(normalize_expt(merged_nos, transform="log2",
                                   filter=TRUE, batch="limmaresid", low_to_zero=TRUE))
merged_nos_limma_metrics <- sm(graph_metrics(merged_nos_limma))

merged_fsva <- sm(normalize_expt(merged_expt, transform="log2",
                              filter=TRUE, batch="fsva", low_to_zero=TRUE))
merged_fsva_metrics <- sm(graph_metrics(merged_fsva))

merged_nor_fsva <- sm(normalize_expt(merged_nor, transform="log2",
                              filter=TRUE, batch="fsva", low_to_zero=TRUE))
merged_nor_fsva_metrics <- sm(graph_metrics(merged_nor_fsva))

merged_nos_fsva <- sm(normalize_expt(merged_nos, transform="log2",
                              filter=TRUE, batch="ssva", low_to_zero=TRUE))
merged_nos_fsva_metrics <- sm(graph_metrics(merged_nos_fsva))

6.0.1 The resulting plots

Why is is suddenly printing stuff now and not before?

merged_pcabatch_metrics$pcaplot

merged_nor_pcabatch_metrics$pcaplot
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse

merged_nos_pcabatch_metrics$pcaplot
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse

merged_sva_metrics$pcaplot

merged_nor_sva_metrics$pcaplot
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse

merged_nos_sva_metrics$pcaplot
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse

merged_combat_metrics$pcaplot

merged_nor_combat_metrics$pcaplot
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse

merged_nos_combat_metrics$pcaplot
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse

merged_limma_metrics$pcaplot

merged_nor_limma_metrics$pcaplot
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse

merged_nos_limma_metrics$pcaplot
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse

merged_fsva_metrics$pcaplot

merged_nor_fsva_metrics$pcaplot
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse

merged_nos_fsva_metrics$pcaplot
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse

7 Write the expt

## hmm I was going to silence this line, but looking at the report it seems to be missing some pictures.
fun_nor <- write_expt(merged_nor, excel=paste0("excel/samples_written_merged_nor-v", ver, ".xlsx"),
                      filter=TRUE, norm="raw", convert="cpm", batch="fsva", transform="log2")
## Writing the legend.
## Writing the raw reads.
## Graphing the raw reads.

## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Writing the normalized reads.
## Graphing the normalized reads.

## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Writing the median reads by factor.
## The factor WT has 6 rows.
## The factor cbf5_D95A has 8 rows.
## The factor upf1d has 4 rows.
## The factor cbf5_D95A upf1d has 2 rows.

LS0tCnRpdGxlOiAiUy4gY2VyZXZpc2lhZSBzYW1wbGUgZXN0aW1hdGlvbiwgbWVyZ2VkIHNhbXBsZSBlZGl0aW9uICgyMDE4MDYwNikuIgphdXRob3I6ICJhdGIgYWJlbGV3QGdtYWlsLmNvbSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiBodG1sX2RvY3VtZW50OgogIGNvZGVfZG93bmxvYWQ6IHRydWUKICBjb2RlX2ZvbGRpbmc6IHNob3cKICBmaWdfY2FwdGlvbjogdHJ1ZQogIGZpZ19oZWlnaHQ6IDcKICBmaWdfd2lkdGg6IDcKICBoaWdobGlnaHQ6IGRlZmF1bHQKICBrZWVwX21kOiBmYWxzZQogIG1vZGU6IHNlbGZjb250YWluZWQKICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICBzZWxmX2NvbnRhaW5lZDogdHJ1ZQogIHRoZW1lOiByZWFkYWJsZQogIHRvYzogdHJ1ZQogIHRvY19mbG9hdDoKICAgIGNvbGxhcHNlZDogZmFsc2UKICAgIHNtb290aF9zY3JvbGw6IGZhbHNlCi0tLQoKPHN0eWxlPgogIGJvZHkgLm1haW4tY29udGFpbmVyIHsKICAgIG1heC13aWR0aDogMTYwMHB4OwogIH0KPC9zdHlsZT4KCmBgYHtyIG9wdGlvbnMsIGluY2x1ZGU9RkFMU0V9CmlmICghaXNUUlVFKGdldDAoInNraXBfbG9hZCIpKSkgewogIGxpYnJhcnkoImhwZ2x0b29scyIpCiAgdHQgPC0gZGV2dG9vbHM6OmxvYWRfYWxsKCJ+L2hwZ2x0b29scyIpCiAga25pdHI6Om9wdHNfa25pdCRzZXQocHJvZ3Jlc3M9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgICB2ZXJib3NlPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgd2lkdGg9OTAsCiAgICAgICAgICAgICAgICAgICAgICAgZWNobz1UUlVFKQogIGtuaXRyOjpvcHRzX2NodW5rJHNldChlcnJvcj1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgICBmaWcud2lkdGg9OCwKICAgICAgICAgICAgICAgICAgICAgICAgZmlnLmhlaWdodD04LAogICAgICAgICAgICAgICAgICAgICAgICBkcGk9OTYpCiAgb2xkX29wdGlvbnMgPC0gb3B0aW9ucyhkaWdpdHM9NCwKICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICBrbml0ci5kdXBsaWNhdGUubGFiZWw9ImFsbG93IikKICAjI2dncGxvdDI6OnRoZW1lX3NldChnZ3Bsb3QyOjp0aGVtZV9idyhiYXNlX3NpemU9MTApKQogIHNldC5zZWVkKDEpCiAgdmVyIDwtICIyMDE4MDYwNiIKICBwcmV2aW91c19maWxlIDwtIHBhc3RlMCgiMDFfYW5ub3RhdGlvbi12IiwgdmVyLCAiLlJtZCIpCgogIHRtcCA8LSB0cnkoc20obG9hZG1lKGZpbGVuYW1lPXBhc3RlMChnc3ViKHBhdHRlcm49IlxcLlJtZCIsIHJlcGxhY2U9IiIsIHg9cHJldmlvdXNfZmlsZSksICItdiIsIHZlciwgIi5yZGEueHoiKSkpKQogIHJtZF9maWxlIDwtIHBhc3RlMCgiMDJfc2FtcGxlX2VzdGltYXRpb25fbWVyZ2VkLXYiLCB2ZXIsICIuUm1kIikKfQpgYGAKClMuIGNlcmV2aXNpYWUgc2FtcGxlIGVzdGltYXRpb24gb2YgYWxsIHNhbXBsZXMgKG9sZCBhbmQgbmV3KQo9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KClRoaXMgZG9jdW1lbnQgc2hvdWxkIG1ha2UgY2xlYXIgdGhlIHN1aXRhYmlsaXR5IG9mIG91ciB5ZWFzdCBkYXRhIGZvciBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbgphbmFseXNlcy4gIEl0IHNob3VsZCBhbHNvIGdpdmUgc29tZSBpZGVhcyBhYm91dCB0aGUgZGVwdGggYW5kIGRpc3RyaWJ1dGlvbiBvZgp0aGUgZGF0YS4KCiMgR2F0aGVyaW5nIHNhbXBsZXMKCkxhdGVyLCB3ZSB3aWxsIGxpa2VseSBjaG9vc2UgdG8gZXhjbHVkZSBvbmUgb2YgdGhlIHRocmVlIGV4cGVyaW1lbnRhbCBiYXRjaGVzIGluCnRoZSBkYXRhLiAgVGhlcmVmb3JlLCBJIGFtIG1ha2luZyB0aHJlZSBleHByZXNzaW9uc2V0cywgb25lIHdpdGggYWxsIGRhdGEsIGFuZApvbmUgdGhlIHZhcmlvdXMgc3Vic2V0cy4KCmBgYHtyIGdhdGhlcl9hbGx9Cm1lcmdlZF9leHB0IDwtIHNtKGNyZWF0ZV9leHB0KG1ldGFkYXRhPSJzYW1wbGVfc2hlZXRzL2FsbF9zYW1wbGVzLnhsc3giLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lX2luZm89c2NfYWxsX2Fubm90YXRpb25zLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlX2NvbHVtbj0iYWxsZmlsZSIpKQojIyBEb24ndCBmb3JnZXQsIEkgbmVlZCB0byBjaGFuZ2UgdGhlIGNvbmRpdGlvbiBuYW1lcy4Kb25seV9vbGQgPC0gc3Vic2V0X2V4cHQobWVyZ2VkX2V4cHQsIHN1YnNldD0iYmF0Y2g9PSdFMSciKQptZXJnZWRfbmV3IDwtIHN1YnNldF9leHB0KG1lcmdlZF9leHB0LCBzdWJzZXQ9ImJhdGNoIT0nRTEnIikKbWVyZ2VkX25vciA8LSBzdWJzZXRfZXhwdChtZXJnZWRfZXhwdCwgc3Vic2V0PSJiYXRjaCE9J0UyQjEnIikKbWVyZ2VkX25vcyA8LSBzdWJzZXRfZXhwdChtZXJnZWRfZXhwdCwgc3Vic2V0PSJiYXRjaCE9J0UyQjInIikKYGBgCgojIFZpc3VhbGl6aW5nIHJhdyBkYXRhCgpUaGVyZSBhcmUgbG90cyBvZiBtZXRob2RzIHdlIGhhdmUgdG8gZXhhbWluZSByYXcgZGF0YSBhbmQgZXhwbG9yZSBzdHVmZiBsaWtlCmJhdGNoIGVmZmVjdHMgb3Igbm9uLWNhbm9uaWNhbCBkaXN0cmlidXRpb25zIG9yIHNrZXdlZCBjb3VudHMuICBocGdsdG9vbHMKcHJvdmlkZXMgc29tZSBmdW5jdGlvbmFsaXR5IHRvIG1ha2UgdGhpcyBwcm9jZXNzIGVhc2llci4gIFRoZSBncmFwaHMgc2hvd24gYmVsb3cKYW5kIG1hbnkgbW9yZSBhcmUgZ2VuZXJhdGVkIHdpdGggdGhlIHdyYXBwZXIgJ2dyYXBoX21ldHJpY3MoKScsIHdoZW4gaW52b2tlZCBpdApwcm92aWRlcyBhIGxpc3Qgb2YgcGxvdHMgaW5jbHVkaW5nOiBsaWJyYXJ5IHNpemVzLCB0aGUgbnVtYmVyIG9mIG5vbi16ZXJvIGdlbmVzLApkZW5zaXR5L2JveCBwbG90cyBieSBzYW1wbGUsIGRpc3RhbmNlL2NvcnJlbGF0aW9uIGhlYXRtYXBzLCBzdGFuZGFyZCBtZWRpYW4KY29ycmVsYXRpb24vZGlzdGFuY2UsIFBDQS9UU05FIGNsdXN0ZXJpbmcsIHRvcC1uIGdlbmVzLCBhIGxlZ2VuZCBkZXNjcmliaW5nIHRoZQpjb2xvcnMvc3ltYm9scyB1c2VkLCBhbmQgc29tZSB0YWJsZXMgZGVzY3JpYmluZyB0aGUgZGF0YS4gIE9wdGlvbmFsbHksIGl0IGNhbgphbHNvIHBlcmZvcm0gcXVhbnRpbGUtcXVhbnRpbGUgcGxvdHMgc2hvd2luZyB0aGUgZGlzdHJpYnV0aW9uIG9mIGVhY2ggc2FtcGxlCnZzLiB0aGUgbWVkaWFuIG9mIGFsbCBzYW1wbGVzIGFuZCBNQSBwbG90cyBvZiB0aGUgc2FtZS4KCkNhdmVhdDogc29tZSBwbG90cyBkbyBub3Qgd29yayB3ZWxsIHdpdGggZ2VuZSBJRHMgdGhhdCBhcmUgYWxsLTAsIHRodXMgSSBmaXJzdApmaWx0ZXIgdGhlIGRhdGEgdG8gcmVtb3ZlIHRoZW0uCgpJIGFsc28gYWRkZWQgYSBuZWF0IGZ1bmN0aW9uICdwbG90X2xpYnNpemVfcHJlcG9zdCgpJyB3aGljaCBzaG93cyBob3cgbWFueSBnZW5lcwphcmUgcG9vcmx5IHJlcHJlc2VudGVkIGJlZm9yZS9hZnRlciBmaWx0ZXJpbmcgdGhlIGRhdGEuCgpUaGUgcGxvdHMgcHJpbnRlZCBoZXJlIGFyZSBhbGwgbWV0cmljcyB3aGljaCBhcmUgdXNlZnVsIHdoZW4gY29uc2lkZXJpbmcgcmF3CmRhdGEuCgpgYGB7ciByYXdfZXhwbG9yZX0KbWVyZ2VkX2ZpbHQgPC0gc20obm9ybWFsaXplX2V4cHQobWVyZ2VkX2V4cHQsIGZpbHRlcj1UUlVFKSkKbWVyZ2VkX21ldHJpY3MgPC0gc20oZ3JhcGhfbWV0cmljcyhtZXJnZWRfZXhwdCkpCgpwcChmaWxlPSJpbGx1c3RyYXRvcl9pbnB1dC8wMV9sZWdlbmQucGRmIiwgaW1hZ2U9bWVyZ2VkX21ldHJpY3MkbGVnZW5kKQpwcChmaWxlPSJpbGx1c3RyYXRvcl9pbnB1dC8wMl9yYXdfbGlic2l6ZS5wZGYiLCBpbWFnZT1tZXJnZWRfbWV0cmljcyRsaWJzaXplKQoKcHJlcG9zdCA8LSBwbG90X2xpYnNpemVfcHJlcG9zdChtZXJnZWRfZXhwdCkKcHAoZmlsZT0iaWxsdXN0cmF0b3JfaW5wdXQvMDNfbGlic2l6ZV9jaGFuZ2VkX2xvd2dlbmVzLnBkZiIsIGltYWdlPXByZXBvc3QkbG93Z2VuZV9wbG90KQoKcHAoZmlsZT0iaWxsdXN0cmF0b3JfaW5wdXQvMDRfbm9uemVyb19nZW5lcy5wZGYiLCBpbWFnZT1tZXJnZWRfbWV0cmljcyRub256ZXJvKQpwcChmaWxlPSJpbGx1c3RyYXRvcl9pbnB1dC8wNV9yYXdfYm94cGxvdC5wZGYiLCBpbWFnZT1tZXJnZWRfbWV0cmljcyRib3hwbG90KQpwcChmaWxlPSJpbGx1c3RyYXRvcl9pbnB1dC8wNl9yYXdfZGVuc2l0eS5wZGYiLCBpbWFnZT1tZXJnZWRfbWV0cmljcyRkZW5zaXR5KQpwcChmaWxlPSJpbGx1c3RyYXRvcl9pbnB1dC8wN19yYXdfYm94cGxvdC5wZGYiLCBpbWFnZT1tZXJnZWRfbWV0cmljcyRib3hwbG90KQpwcChmaWxlPSJpbGx1c3RyYXRvcl9pbnB1dC8wOF90b3BuLnBkZiIsIGltYWdlPW1lcmdlZF9tZXRyaWNzJHRvcG5wbG90KQpgYGAKCiMgTm9ybWFsaXplIGFuZCB2aXN1YWxpemUKCk90aGVyIG1ldHJpY3MgYXJlIG1vcmUgdXNlZnVsIHdoZW4gdXNlZCB3aXRoIGRhdGEgb24gdGhlIGxvZyBzY2FsZSBhbmQKbm9ybWFsaXplZCBieSBudW1iZXIgb2YgcmVhZHMvbGlicmFyeSBhbmQvb3IgYnkgcXVhbnRpbGUuCgpgYGB7ciBub3JtYWxpemUsIGZpZy5zaG93PSJoaWRlIn0KbWVyZ2VkX25vcm0gPC0gbm9ybWFsaXplX2V4cHQobWVyZ2VkX2V4cHQsIHRyYW5zZm9ybT0ibG9nMiIsIGNvbnZlcnQ9ImNwbSIsIGZpbHRlcj1UUlVFKQptZXJnZWRfbWV0cmljcyA8LSBncmFwaF9tZXRyaWNzKG1lcmdlZF9ub3JtKQpgYGAKClRoZSBkYXRhIHNob3VsZCBub3cgYmUgbm9ybWFsaXplZCwgbGV0cyB2aWV3IHNvbWUgbWV0cmljcyBwb3N0LWZhY3RvLgoKYGBge3Igbm9ybXZpen0KcHAoZmlsZT0iaWxsdXN0cmF0b3JfaW5wdXQvMDlfbm9ybV9jb3JoZWF0LnBkZiIsIGltYWdlPW1lcmdlZF9tZXRyaWNzJGNvcmhlYXQpCnBwKGZpbGU9ImlsbHVzdHJhdG9yX2lucHV0LzEwX25vcm1fZGlzaGVhdC5wZGYiLCBpbWFnZT1tZXJnZWRfbWV0cmljcyRkaXNoZWF0KQojIyBJdCBhcHBlYXJzIHRoYXQganVzdCB0aGUgbm9ybWFsaXphdGlvbiBpcyBzdWZmaWNpZW50IHRvIHNwbGl0IHRoZSBzYW1wbGVzIGNvbXBsZXRlbHkgYnkgdHlwZSBhbmQgZGVlcGx5IHNlcGFyYXRlIHRoZW0gZnJvbSB0aGUgaGV0ZXJvbG9nb3VzIHNhbXBsZXMKCnBwKGZpbGU9ImlsbHVzdHJhdG9yX2lucHV0LzExX25vcm1fc21jLnBkZiIsIGltYWdlPW1lcmdlZF9tZXRyaWNzJHNtYykKcHAoZmlsZT0iaWxsdXN0cmF0b3JfaW5wdXQvMTJfbm9ybV9zbWQucGRmIiwgaW1hZ2U9bWVyZ2VkX21ldHJpY3Mkc21kKQojIyBUaGUgc2FtcGxlcyBhcmUgdmVyeSB3ZWxsIGJlaGF2ZWQsIG5vbmUgZmFsbCBiZWxvdyB0aGUgcmVkIGxpbmUuCgpwcChmaWxlPSJpbGx1c3RyYXRvcl9pbnB1dC8xM19ub3JtX3BjYS5wZGYiLCBpbWFnZT1tZXJnZWRfbWV0cmljcyRwY2FwbG90KQpwcChmaWxlPSJpbGx1c3RyYXRvcl9pbnB1dC8xNF9ub3JtX3RzbmUucGRmIiwgaW1hZ2U9bWVyZ2VkX21ldHJpY3MkdHNuZXBsb3QpCiMjIFRoZSBob21vZ2VuZW91cyB3dC9tdXRhbnQgYXJlIG5pY2VseSBzZXBhcmF0ZWQsIGFuZCB3aGF0IGlzIG1vcmUsIHRoZSBleG9nZW5lb3VzIHNhbXBsZXMgYWxzbyBzcGxpdCB3dC9tdXRhbnQsIHRoYXQgbWlnaHQgcHJvdmUgdG8gYmUgcXVpdGUgdXNlZnVsLgpgYGAKCiMjIFByaW50IHNvbWUgdmFyaWFuY2UgcGFydGl0aW9uIGluZm9ybWF0aW9uCgpUaGlzIGlzIGFuIGludGVyZXN0aW5nIGFzaWRlIHdoaWNoIGNhbWUgdXAgbGFzdCB3ZWVrIGZvciBzb21lIG90aGVyIGRhdGEuICBJdAptaWdodCBiZSBnb29kIHRvIGluY2x1ZGUgdGhlICUgdmFyaWFuY2UgY29ycmVsYXRlZCB3aXRoICdjb25kaXRpb24nIGFzIGEgY29sdW1uCmluIHRoZSBhbm5vdGF0aW9uIGRhdGEgZm9yIHRoZSBleHByZXNzaW9uc2V0LiAgVGh1cywgd2hlbiB3ZSBkbyB0aGUgZGlmZmVyZW50aWFsCmV4cHJlc3Npb24gYW5hbHlzaXMgbGF0ZXIsIHdlIGNhbiBsb29rIGFuZCBzZWUgaWYgYSAnc2lnbmlmaWNhbnQnIGdlbmUgaGFzCnZhcmlhbmNlIHdoaWNoIGlzIGFjdHVhbGx5IGNvcnJlbGF0ZWQgd2l0aCBjb25kaXRpb24uCgpTaW5jZSB3cml0aW5nIHRoZXNlIGFuYWx5c2VzLCBJIGltcGxlbWVudGVkIHRoaXMgaWRlYSBhbmQgc28gYW0gaW5jbHVkaW5nIGl0IGhlcmUuCgpgYGB7ciB2YXJpYW5jZV9wYXJ0aXRpb25zfQp2cCA8LSB2YXJwYXJ0KG1lcmdlZF9leHB0LCBwcmVkaWN0b3I9TlVMTCwgZmFjdG9ycz1jKCJjb25kaXRpb24iLCAiYmF0Y2giKSkKcHAoZmlsZT0iaWxsdXN0cmF0b3JfaW5wdXQvMTVfbWVyZ2VkX3ZhcnBhcnRfcGFydGl0aW9uLnBkZiIsIGltYWdlPXZwJHBhcnRpdGlvbl9wbG90KQojIyBDaGVjayBvdXQgdGhlIGxhc3QgdHdvIGNvbHVtbnMhCmhlYWQoZkRhdGEodnAkbW9kaWZpZWRfZXhwdCkpCgptZXJnZWRfc3ZhIDwtIHNtKG5vcm1hbGl6ZV9leHB0KG1lcmdlZF9leHB0LCB0cmFuc2Zvcm09ImxvZzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcj1UUlVFLCBiYXRjaD0ic3ZhIiwgbG93X3RvX3plcm89VFJVRSkpCnZwc3ZhIDwtIHZhcnBhcnQobWVyZ2VkX3N2YSwgcHJlZGljdG9yPU5VTEwsIGZhY3RvcnM9YygiY29uZGl0aW9uIiwgImJhdGNoIikpCnBwKGZpbGU9ImlsbHVzdHJhdG9yX2lucHV0LzE2X21lcmdlZF92YXJwYXJ0X3N2YV9wYXJ0aXRpb24ucGRmIiwgaW1hZ2U9dnBzdmEkcGFydGl0aW9uX3Bsb3QpCmhlYWQoZkRhdGEodnBzdmEkbW9kaWZpZWRfZXhwdCkpCmBgYAoKIyBOb3cgbG9vayBhdCB0aGUgZGF0YSB3aXRob3V0IGJhdGNoICdFMkIxJwoKYGBge3Igbm9yLCBmaWcuc2hvdz0iaGlkZSJ9Cm5vcl9ub3JtIDwtIHNtKG5vcm1hbGl6ZV9leHB0KG1lcmdlZF9ub3IsIHRyYW5zZm9ybT0ibG9nMiIsIGNvbnZlcnQ9ImNwbSIsIG5vcm09InF1YW50IiwgZmlsdGVyPVRSVUUpKQpub3JfcGxvdHMgPC0gc20oZ3JhcGhfbWV0cmljcyhub3Jfbm9ybSkpCm5vcl9iYXRjaG5vcm0gPC0gc20obm9ybWFsaXplX2V4cHQobWVyZ2VkX25vciwgdHJhbnNmb3JtPSJsb2cyIiwgY29udmVydD0iY3BtIiwgbm9ybT0icXVhbnQiLCBmaWx0ZXI9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYXRjaD0iZnN2YSIpKQpub3JfYmF0Y2hwbG90cyA8LSBzbShncmFwaF9tZXRyaWNzKG5vcl9iYXRjaG5vcm0pKQpgYGAKCiMjIFByaW50IHRoZSBzbWFsbGVyIHNldCBvZiBkYXRhCgpgYGB7ciBub3Jfc2hvd30KIyMgQmVmb3JlIGZzdmEsIGNvcnJlbGF0aW9uIGhlYXRtYXAgd2l0aG91dCAncicKcHAoZmlsZT0iaWxsdXN0cmF0b3JfaW5wdXQvMTdfbm9yX2NvcmhlYXQucGRmIiwgaW1hZ2U9bm9yX3Bsb3RzJGNvcmhlYXQpCiMjIEJlZm9yZSBmc3ZhLCBwY2Egd2l0aG91dCAncicKcHAoZmlsZT0iaWxsdXN0cmF0b3JfaW5wdXQvMThfbm9yX3BjYS5wZGYiLCBpbWFnZT1ub3JfcGxvdHMkcGNhcGxvdCkKIyMgQWZ0ZXIgZnN2YSwgY29ycmVsYXRpb24gaGVhdG1hcCB3aXRob3V0ICdyJwpwcChmaWxlPSJpbGx1c3RyYXRvcl9pbnB1dC8xOV9ub3JfZnN2YV9jb3JoZWF0LnBkZiIsIGltYWdlPW5vcl9iYXRjaHBsb3RzJGNvcmhlYXQpCiMjIEFmdGVyIGZzdmEsIHBjYSB3aXRob3V0ICdyJwpwcChmaWxlPSJpbGx1c3RyYXRvcl9pbnB1dC8yMF9ub3JfZnN2YV9wY2EucGRmIiwgaW1hZ2U9bm9yX2JhdGNocGxvdHMkcGNhcGxvdCkKYGBgCgojIFRyeSBtYW55IGJhdGNoIGVzdGltYXRpb24gbWV0aG9kcyB0byBzZWUgd2hhdCBpcyB1cC4KCkkgZG8gbm90IHRoaW5rIGFueSBvZiB0aGlzIGluZm9ybWF0aW9uIGlzIGN1cnJlbnRseSBiZWluZyB1c2VkLCBzbyBJIGFtIGdvaW5nIHRvCnN0b3AgcnVubmluZyBpdCBmb3IgdGhlIG1vbWVudCBidXQga2VlcCBpdCBoZXJlIGluIGNhc2Ugd2UgZGVjaWRlIHRvIHJldml2ZSBpdC4KCmBgYHtyIGJhdGNoX2V4bywgZmlnLnNob3c9RkFMU0V9Cm1lcmdlZF9wY2FiYXRjaCA8LSBzbShub3JtYWxpemVfZXhwdChtZXJnZWRfZXhwdCwgdHJhbnNmb3JtPSJsb2cyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXI9VFJVRSwgYmF0Y2g9InBjYSIsIGxvd190b196ZXJvPVRSVUUpKQptZXJnZWRfcGNhYmF0Y2hfbWV0cmljcyA8LSBzbShncmFwaF9tZXRyaWNzKG1lcmdlZF9wY2FiYXRjaCkpCgptZXJnZWRfbm9yX3BjYWJhdGNoIDwtIHNtKG5vcm1hbGl6ZV9leHB0KG1lcmdlZF9ub3IsIHRyYW5zZm9ybT0ibG9nMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyPVRSVUUsIGJhdGNoPSJwY2EiLCBsb3dfdG9femVybz1UUlVFKSkKbWVyZ2VkX25vcl9wY2FiYXRjaF9tZXRyaWNzIDwtIHNtKGdyYXBoX21ldHJpY3MobWVyZ2VkX25vcl9wY2FiYXRjaCkpCgptZXJnZWRfbm9zX3BjYWJhdGNoIDwtIHNtKG5vcm1hbGl6ZV9leHB0KG1lcmdlZF9ub3MsIHRyYW5zZm9ybT0ibG9nMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyPVRSVUUsIGJhdGNoPSJwY2EiLCBsb3dfdG9femVybz1UUlVFKSkKbWVyZ2VkX25vc19wY2FiYXRjaF9tZXRyaWNzIDwtIHNtKGdyYXBoX21ldHJpY3MobWVyZ2VkX25vc19wY2FiYXRjaCkpCgptZXJnZWRfc3ZhIDwtIHNtKG5vcm1hbGl6ZV9leHB0KG1lcmdlZF9leHB0LCB0cmFuc2Zvcm09ImxvZzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcj1UUlVFLCBiYXRjaD0ic3ZhIiwgbG93X3RvX3plcm89VFJVRSkpCm1lcmdlZF9zdmFfbWV0cmljcyA8LSBzbShncmFwaF9tZXRyaWNzKG1lcmdlZF9zdmEpKQoKbWVyZ2VkX25vcl9zdmEgPC0gc20obm9ybWFsaXplX2V4cHQobWVyZ2VkX25vciwgdHJhbnNmb3JtPSJsb2cyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXI9VFJVRSwgYmF0Y2g9InN2YSIsIGxvd190b196ZXJvPVRSVUUpKQptZXJnZWRfbm9yX3N2YV9tZXRyaWNzIDwtIHNtKGdyYXBoX21ldHJpY3MobWVyZ2VkX25vcl9zdmEpKQoKbWVyZ2VkX25vc19zdmEgPC0gc20obm9ybWFsaXplX2V4cHQobWVyZ2VkX25vcywgdHJhbnNmb3JtPSJsb2cyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXI9VFJVRSwgYmF0Y2g9InN2YSIsIGxvd190b196ZXJvPVRSVUUpKQptZXJnZWRfbm9zX3N2YV9tZXRyaWNzIDwtIHNtKGdyYXBoX21ldHJpY3MobWVyZ2VkX25vc19zdmEpKQoKbWVyZ2VkX2NvbWJhdCA8LSBzbShub3JtYWxpemVfZXhwdChtZXJnZWRfZXhwdCwgdHJhbnNmb3JtPSJsb2cyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXI9VFJVRSwgYmF0Y2g9ImNvbWJhdF9zY2FsZSIsIGxvd190b196ZXJvPVRSVUUpKQptZXJnZWRfY29tYmF0X21ldHJpY3MgPC0gc20oZ3JhcGhfbWV0cmljcyhtZXJnZWRfY29tYmF0KSkKCm1lcmdlZF9ub3JfY29tYmF0IDwtIHNtKG5vcm1hbGl6ZV9leHB0KG1lcmdlZF9ub3IsIHRyYW5zZm9ybT0ibG9nMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyPVRSVUUsIGJhdGNoPSJjb21iYXRfc2NhbGUiLCBsb3dfdG9femVybz1UUlVFKSkKbWVyZ2VkX25vcl9jb21iYXRfbWV0cmljcyA8LSBzbShncmFwaF9tZXRyaWNzKG1lcmdlZF9ub3JfY29tYmF0KSkKCm1lcmdlZF9ub3NfY29tYmF0IDwtIHNtKG5vcm1hbGl6ZV9leHB0KG1lcmdlZF9ub3MsIHRyYW5zZm9ybT0ibG9nMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyPVRSVUUsIGJhdGNoPSJjb21iYXRfc2NhbGUiLCBsb3dfdG9femVybz1UUlVFKSkKbWVyZ2VkX25vc19jb21iYXRfbWV0cmljcyA8LSBzbShncmFwaF9tZXRyaWNzKG1lcmdlZF9ub3NfY29tYmF0KSkKCm1lcmdlZF9saW1tYSA8LSBzbShub3JtYWxpemVfZXhwdChtZXJnZWRfZXhwdCwgdHJhbnNmb3JtPSJsb2cyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXI9VFJVRSwgYmF0Y2g9ImxpbW1hcmVzaWQiLCBsb3dfdG9femVybz1UUlVFKSkKbWVyZ2VkX2xpbW1hX21ldHJpY3MgPC0gc20oZ3JhcGhfbWV0cmljcyhtZXJnZWRfbGltbWEpKQoKbWVyZ2VkX25vcl9saW1tYSA8LSBzbShub3JtYWxpemVfZXhwdChtZXJnZWRfbm9yLCB0cmFuc2Zvcm09ImxvZzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcj1UUlVFLCBiYXRjaD0ibGltbWFyZXNpZCIsIGxvd190b196ZXJvPVRSVUUpKQptZXJnZWRfbm9yX2xpbW1hX21ldHJpY3MgPC0gc20oZ3JhcGhfbWV0cmljcyhtZXJnZWRfbm9yX2xpbW1hKSkKCm1lcmdlZF9ub3NfbGltbWEgPC0gc20obm9ybWFsaXplX2V4cHQobWVyZ2VkX25vcywgdHJhbnNmb3JtPSJsb2cyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXI9VFJVRSwgYmF0Y2g9ImxpbW1hcmVzaWQiLCBsb3dfdG9femVybz1UUlVFKSkKbWVyZ2VkX25vc19saW1tYV9tZXRyaWNzIDwtIHNtKGdyYXBoX21ldHJpY3MobWVyZ2VkX25vc19saW1tYSkpCgptZXJnZWRfZnN2YSA8LSBzbShub3JtYWxpemVfZXhwdChtZXJnZWRfZXhwdCwgdHJhbnNmb3JtPSJsb2cyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyPVRSVUUsIGJhdGNoPSJmc3ZhIiwgbG93X3RvX3plcm89VFJVRSkpCm1lcmdlZF9mc3ZhX21ldHJpY3MgPC0gc20oZ3JhcGhfbWV0cmljcyhtZXJnZWRfZnN2YSkpCgptZXJnZWRfbm9yX2ZzdmEgPC0gc20obm9ybWFsaXplX2V4cHQobWVyZ2VkX25vciwgdHJhbnNmb3JtPSJsb2cyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyPVRSVUUsIGJhdGNoPSJmc3ZhIiwgbG93X3RvX3plcm89VFJVRSkpCm1lcmdlZF9ub3JfZnN2YV9tZXRyaWNzIDwtIHNtKGdyYXBoX21ldHJpY3MobWVyZ2VkX25vcl9mc3ZhKSkKCm1lcmdlZF9ub3NfZnN2YSA8LSBzbShub3JtYWxpemVfZXhwdChtZXJnZWRfbm9zLCB0cmFuc2Zvcm09ImxvZzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXI9VFJVRSwgYmF0Y2g9InNzdmEiLCBsb3dfdG9femVybz1UUlVFKSkKbWVyZ2VkX25vc19mc3ZhX21ldHJpY3MgPC0gc20oZ3JhcGhfbWV0cmljcyhtZXJnZWRfbm9zX2ZzdmEpKQpgYGAKCiMjIyBUaGUgcmVzdWx0aW5nIHBsb3RzCgpXaHkgaXMgaXMgc3VkZGVubHkgcHJpbnRpbmcgc3R1ZmYgbm93IGFuZCBub3QgYmVmb3JlPwoKYGBge3IgYmF0Y2hfZXN0aW1hdGlvbl9wbG90c30KbWVyZ2VkX3BjYWJhdGNoX21ldHJpY3MkcGNhcGxvdAptZXJnZWRfbm9yX3BjYWJhdGNoX21ldHJpY3MkcGNhcGxvdAptZXJnZWRfbm9zX3BjYWJhdGNoX21ldHJpY3MkcGNhcGxvdAptZXJnZWRfc3ZhX21ldHJpY3MkcGNhcGxvdAptZXJnZWRfbm9yX3N2YV9tZXRyaWNzJHBjYXBsb3QKbWVyZ2VkX25vc19zdmFfbWV0cmljcyRwY2FwbG90Cm1lcmdlZF9jb21iYXRfbWV0cmljcyRwY2FwbG90Cm1lcmdlZF9ub3JfY29tYmF0X21ldHJpY3MkcGNhcGxvdAptZXJnZWRfbm9zX2NvbWJhdF9tZXRyaWNzJHBjYXBsb3QKbWVyZ2VkX2xpbW1hX21ldHJpY3MkcGNhcGxvdAptZXJnZWRfbm9yX2xpbW1hX21ldHJpY3MkcGNhcGxvdAptZXJnZWRfbm9zX2xpbW1hX21ldHJpY3MkcGNhcGxvdAptZXJnZWRfZnN2YV9tZXRyaWNzJHBjYXBsb3QKbWVyZ2VkX25vcl9mc3ZhX21ldHJpY3MkcGNhcGxvdAptZXJnZWRfbm9zX2ZzdmFfbWV0cmljcyRwY2FwbG90CmBgYAoKIyBXcml0ZSB0aGUgZXhwdAoKYGBge3IgZnN2YV93cml0dGVufQojIyBobW0gSSB3YXMgZ29pbmcgdG8gc2lsZW5jZSB0aGlzIGxpbmUsIGJ1dCBsb29raW5nIGF0IHRoZSByZXBvcnQgaXQgc2VlbXMgdG8gYmUgbWlzc2luZyBzb21lIHBpY3R1cmVzLgpmdW5fbm9yIDwtIHdyaXRlX2V4cHQobWVyZ2VkX25vciwgZXhjZWw9cGFzdGUwKCJleGNlbC9zYW1wbGVzX3dyaXR0ZW5fbWVyZ2VkX25vci12IiwgdmVyLCAiLnhsc3giKSwKICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcj1UUlVFLCBub3JtPSJyYXciLCBjb252ZXJ0PSJjcG0iLCBiYXRjaD0iZnN2YSIsIHRyYW5zZm9ybT0ibG9nMiIpCmBgYAoKYGBge3Igc2F2ZW1lLCBpbmNsdWRlPUZBTFNFfQppZiAoIWlzVFJVRShnZXQwKCJza2lwX2xvYWQiKSkpIHsKICBwYW5kZXI6OnBhbmRlcihzZXNzaW9uSW5mbygpKQogIG1lc3NhZ2UocGFzdGUwKCJUaGlzIGlzIGhwZ2x0b29scyBjb21taXQ6ICIsIGdldF9naXRfY29tbWl0KCkpKQogIHRoaXNfc2F2ZSA8LSBwYXN0ZTAoZ3N1YihwYXR0ZXJuPSJcXC5SbWQiLCByZXBsYWNlPSIiLCB4PXJtZF9maWxlKSwgIi12IiwgdmVyLCAiLnJkYS54eiIpCiAgdG1wIDwtIHNtKHNhdmVtZShmaWxlbmFtZT10aGlzX3NhdmUpKQp9CmBgYAo=